# 工作流管理模块
import os
import json
import time
import threading
import logging
from datetime import datetime
from typing import List, Dict, Any, Optional
import uuid

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("WorkflowManager")

# 尝试导入必要的库
try:
    import pyautogui
    logger.info("pyautogui导入成功")
    PYAUTOGUI_AVAILABLE = True
except ImportError:
    logger.warning("pyautogui未安装，鼠标和键盘控制功能将不可用")
    logger.warning("请运行: pip install pyautogui")
    PYAUTOGUI_AVAILABLE = False

try:
    import keyboard
    logger.info("keyboard导入成功")
    KEYBOARD_AVAILABLE = True
    # 检查键盘钩子是否可用
    try:
        # 尝试注册一个简单的热键测试
        def dummy_hook():
            pass
        keyboard.add_hotkey('ctrl+alt+d', dummy_hook)
        keyboard.remove_hotkey('ctrl+alt+d')
        KEYBOARD_HOOK_AVAILABLE = True
    except Exception as e:
        logger.warning(f"键盘钩子不可用: {str(e)}")
        KEYBOARD_HOOK_AVAILABLE = False
except ImportError:
    logger.warning("keyboard未安装，键盘事件监听功能将不可用")
    logger.warning("请运行: pip install keyboard")
    KEYBOARD_AVAILABLE = False
    KEYBOARD_HOOK_AVAILABLE = False

class ActionRecorder:
    """操作录制器，用于录制用户的鼠标和键盘操作"""
    
    def __init__(self):
        self.recording = False
        self.actions = []
        self.start_time = None
        self.last_time = None
        self.recording_lock = threading.RLock()
        self.stop_event = threading.Event()
        # 保存可用功能状态
        self.keyboard_available = KEYBOARD_AVAILABLE
        self.keyboard_hook_available = KEYBOARD_HOOK_AVAILABLE
        self.pyautogui_available = PYAUTOGUI_AVAILABLE
        
        # 记录初始化状态
        available_features = []
        if self.keyboard_available:
            available_features.append("键盘事件")
        if self.pyautogui_available:
            available_features.append("鼠标事件")
        
        if available_features:
            logger.info(f"ActionRecorder初始化完成，可用功能: {', '.join(available_features)}")
        else:
            logger.warning("ActionRecorder初始化完成，但缺少必要依赖，所有记录功能不可用")
    
    def start_recording(self) -> None:
        """开始录制操作"""
        # 检查是否有可用的记录功能
        if not (self.keyboard_available or self.pyautogui_available):
            logger.error("缺少必要依赖，无法开始录制")
            return
            
        with self.recording_lock:
            if self.recording:
                logger.warning("录制已经在进行中")
                return
            
            self.recording = True
            self.actions = []
            self.start_time = time.time()
            self.last_time = self.start_time
            self.stop_event.clear()
            logger.info("开始录制操作")
    
    def stop_recording(self) -> List[Dict[str, Any]]:
        """停止录制操作并返回录制的操作列表"""
        with self.recording_lock:
            if not self.recording:
                logger.warning("没有正在进行的录制")
                return []
            
            self.recording = False
            self.stop_event.set()
            logger.info(f"停止录制，共录制了 {len(self.actions)} 个操作")
            return self.actions.copy()
    
    def record_mouse_move(self, x: int, y: int) -> None:
        """记录鼠标移动"""
        if not self.recording or not self.pyautogui_available:
            return
        
        current_time = time.time()
        delay = current_time - self.last_time
        self.last_time = current_time
        
        with self.recording_lock:
            self.actions.append({
                "type": "mouse_move",
                "x": x,
                "y": y,
                "delay": delay
            })
    
    def record_mouse_click(self, x: int, y: int, button: str = "left") -> None:
        """记录鼠标点击"""
        if not self.recording or not self.pyautogui_available:
            return
        
        current_time = time.time()
        delay = current_time - self.last_time
        self.last_time = current_time
        
        with self.recording_lock:
            self.actions.append({
                "type": "mouse_click",
                "x": x,
                "y": y,
                "button": button,
                "delay": delay
            })
    
    def record_mouse_scroll(self, x: int, y: int, dx: int, dy: int) -> None:
        """记录鼠标滚轮滚动"""
        if not self.recording or not self.pyautogui_available:
            return
        
        current_time = time.time()
        delay = current_time - self.last_time
        self.last_time = current_time
        
        with self.recording_lock:
            self.actions.append({
                "type": "mouse_scroll",
                "x": x,
                "y": y,
                "dx": dx,
                "dy": dy,
                "delay": delay
            })
    
    def record_key_press(self, key: str) -> None:
        """记录键盘按键"""
        if not self.recording or not self.keyboard_available:
            return
        
        current_time = time.time()
        delay = current_time - self.last_time
        self.last_time = current_time
        
        with self.recording_lock:
            self.actions.append({
                "type": "key_press",
                "key": key,
                "delay": delay
            })
    
    def save_recording(self, filename: str = None) -> str:
        """保存录制的操作到文件"""
        if not self.actions:
            logger.warning("没有录制的操作可保存")
            return "没有录制的操作可保存"
        
        if not filename:
            # 生成默认文件名
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"workflow_{timestamp}.json"
            
        # 确保文件名有.json扩展名
        if not filename.endswith(".json"):
            filename += ".json"
        
        # 保存到工作流目录
        workflow_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "workflows")
        os.makedirs(workflow_dir, exist_ok=True)
        filepath = os.path.join(workflow_dir, filename)
        
        try:
            with open(filepath, "w", encoding="utf-8") as f:
                json.dump({
                    "metadata": {
                        "created_at": datetime.now().isoformat(),
                        "action_count": len(self.actions),
                        "workflow_id": str(uuid.uuid4())
                    },
                    "actions": self.actions
                }, f, ensure_ascii=False, indent=2)
            
            logger.info(f"工作流已保存到: {filepath}")
            return f"工作流已保存到: {filepath}"
        except Exception as e:
            logger.error(f"保存工作流失败: {str(e)}")
            return f"保存工作流失败: {str(e)}"

class ActionPlayer:
    """操作播放器，用于回放录制的操作序列"""
    
    def __init__(self):
        self.playing = False
        self.stop_event = threading.Event()
        self.playback_lock = threading.RLock()
        # 保存可用功能状态
        self.keyboard_available = KEYBOARD_AVAILABLE
        self.pyautogui_available = PYAUTOGUI_AVAILABLE
        
        # 记录初始化状态
        available_features = []
        if self.keyboard_available:
            available_features.append("键盘事件")
        if self.pyautogui_available:
            available_features.append("鼠标事件")
        
        if available_features:
            logger.info(f"ActionPlayer初始化完成，可用功能: {', '.join(available_features)}")
        else:
            logger.warning("ActionPlayer初始化完成，但缺少必要依赖，所有播放功能不可用")
    
    def play_actions(self, actions: List[Dict[str, Any]], speed_factor: float = 1.0) -> str:
        """回放操作序列"""
        with self.playback_lock:
            if self.playing:
                return "正在播放其他工作流，请先停止当前播放"
            
            # 检查是否有可用的播放功能
            if not (self.keyboard_available or self.pyautogui_available):
                logger.error("缺少必要依赖，无法开始播放")
                return "缺少必要依赖，无法开始播放"
            
            self.playing = True
            self.stop_event.clear()
            
            try:
                logger.info(f"开始播放工作流，共 {len(actions)} 个操作，速度因子: {speed_factor}")
                
                for i, action in enumerate(actions):
                    if self.stop_event.is_set():
                        return f"工作流播放已停止，已执行 {i} 个操作"
                    
                    # 等待指定的延迟时间
                    delay = action.get("delay", 0) / speed_factor
                    if delay > 0:
                        time.sleep(min(delay, 5))  # 限制最大延迟为5秒
                    
                    # 执行操作
                    try:
                        self._execute_action(action)
                    except Exception as e:
                        logger.error(f"执行操作失败 (索引 {i}): {str(e)}")
                        return f"工作流执行出错: {str(e)}"
                
                logger.info("工作流播放完成")
                return "工作流播放完成"
            finally:
                self.playing = False
    
    def stop_playback(self) -> None:
        """停止播放操作序列"""
        self.stop_event.set()
        logger.info("停止工作流播放")
    
    def _execute_action(self, action: Dict[str, Any]) -> None:
        """执行单个操作"""
        action_type = action.get("type")
        
        if action_type == "mouse_move" and self.pyautogui_available:
            pyautogui.moveTo(action["x"], action["y"])
        elif action_type == "mouse_click" and self.pyautogui_available:
            pyautogui.click(action["x"], action["y"], button=action.get("button", "left"))
        elif action_type == "mouse_scroll" and self.pyautogui_available:
            pyautogui.scroll(action["dy"], x=action["x"], y=action["y"])
        elif action_type == "key_press" and self.keyboard_available:
            key = action["key"]
            # 处理特殊按键
            if key.startswith("special_"):
                # 特殊按键处理
                special_key = key[8:]  # 去掉 "special_" 前缀
                if self.pyautogui_available and hasattr(pyautogui, special_key):
                    getattr(pyautogui, special_key)()
                elif self.keyboard_available:
                    keyboard.press_and_release(special_key)
            else:
                pyautogui.press(key) if self.pyautogui_available else keyboard.press_and_release(key)
    
    def load_and_play(self, filename: str, speed_factor: float = 1.0) -> str:
        """加载并播放工作流文件"""
        # 尝试从工作流目录加载
        workflow_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "workflows")
        filepath = os.path.join(workflow_dir, filename)
        
        # 如果文件路径不存在，尝试添加.json扩展名
        if not os.path.exists(filepath) and not filename.endswith(".json"):
            filepath += ".json"
        
        if not os.path.exists(filepath):
            logger.error(f"工作流文件不存在: {filepath}")
            return f"工作流文件不存在: {filepath}"
        
        try:
            with open(filepath, "r", encoding="utf-8") as f:
                data = json.load(f)
            
            actions = data.get("actions", [])
            if not actions:
                return "工作流文件中没有操作序列"
            
            logger.info(f"从文件加载工作流: {filepath}")
            return self.play_actions(actions, speed_factor)
        except Exception as e:
            logger.error(f"加载工作流文件失败: {str(e)}")
            return f"加载工作流文件失败: {str(e)}"

# 工作流管理模块 - 负责记录和回放用户操作
class WorkflowManager:
    """工作流管理器，整合录制和播放功能"""
    
    def __init__(self):
        self.action_recorder = ActionRecorder()
        self.action_player = ActionPlayer()
        self.current_workflow = None
        self.is_recording = False
        self.recording_thread = None
        self.workflows_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "workflows")
        
        # 记录功能状态
        self.pyautogui_available = PYAUTOGUI_AVAILABLE
        self.keyboard_available = KEYBOARD_AVAILABLE
        self.keyboard_hook_available = KEYBOARD_HOOK_AVAILABLE
        
        # 确保工作流目录存在
        if not os.path.exists(self.workflows_dir):
            os.makedirs(self.workflows_dir)
            logger.info(f"创建工作流目录: {self.workflows_dir}")
        
        logger.info(f"WorkflowManager初始化 - 功能状态: 鼠标控制={self.pyautogui_available}, " \
                   f"键盘控制={self.keyboard_available}, 键盘钩子={self.keyboard_hook_available}")
        logger.info("工作流管理器初始化完成")
    
    def start_recording(self, workflow_name=None) -> str:
        """开始录制工作流"""
        if self.is_recording:
            return "已经在录制工作流"
        
        # 检查是否有任何可用功能
        if not (self.pyautogui_available or self.keyboard_available):
            logger.error("无法开始录制：缺少pyautogui和keyboard依赖")
            return "无法开始录制：缺少pyautogui和keyboard依赖"
        
        self.is_recording = True
        if workflow_name:
            self.current_workflow = workflow_name
        
        # 启动录制线程
        self.recording_thread = threading.Thread(target=self._recording_loop)
        self.recording_thread.daemon = True
        self.recording_thread.start()
        self.action_recorder.start_recording()
        
        return "开始录制工作流，请执行您想要录制的操作\n按Ctrl+Shift+R停止录制"
    
    def stop_recording(self, save: bool = True, filename: str = None) -> str:
        """停止录制工作流"""
        if not self.is_recording:
            return "没有正在进行的录制"
        
        self.is_recording = False
        actions = self.action_recorder.stop_recording()
        
        if not actions:
            return "没有录制到任何操作"
        
        if save:
            return self.action_recorder.save_recording(filename)
        else:
            return f"停止录制，共录制了 {len(actions)} 个操作（未保存）"
    
    def _recording_loop(self) -> None:
        """录制循环，监听鼠标和键盘事件"""
        # 设置键盘事件钩子
        def on_key_press(event):
            if event.name == 'r' and keyboard.is_pressed('ctrl') and keyboard.is_pressed('shift'):
                # Ctrl+Shift+R 停止录制
                self.stop_recording()
                return False  # 停止事件传播
            
            if self.is_recording:
                # 记录按键
                self.action_recorder.record_key_press(event.name)
        
        # 注册按键事件
        keyboard.hook(on_key_press)
        
        # 记录鼠标位置
        last_x, last_y = pyautogui.position()
        
        try:
            while self.is_recording:
                # 检查鼠标位置
                x, y = pyautogui.position()
                if x != last_x or y != last_y:
                    self.action_recorder.record_mouse_move(x, y)
                    last_x, last_y = x, y
                
                # 检查鼠标点击
                if pyautogui.mouseDown():
                    button = "left" if pyautogui.mouseDown(button='left') else "right"
                    self.action_recorder.record_mouse_click(x, y, button)
                
                # 检查鼠标滚轮
                # 注意：pyautogui没有直接检测滚轮的方法，这里简化处理
                
                time.sleep(0.05)  # 避免CPU过度使用
        finally:
            # 移除键盘钩子
            keyboard.unhook_all()
    
    def play_workflow(self, filename: Optional[str] = None, actions: Optional[List[Dict[str, Any]]] = None, 
                     speed_factor: float = 1.0) -> str:
        """播放工作流"""
        # 检查是否有任何可用功能
        if not (self.pyautogui_available or self.keyboard_available):
            return "无法播放工作流：缺少pyautogui和keyboard依赖"
        
        if filename:
            return self.action_player.load_and_play(filename, speed_factor)
        elif actions:
            return self.action_player.play_actions(actions, speed_factor)
        else:
            return "请提供工作流文件名或操作序列"
    
    def stop_playback(self) -> str:
        """停止工作流播放"""
        self.action_player.stop_playback()
        return "停止工作流播放"
    
    def list_workflows(self) -> str:
        """列出所有保存的工作流"""
        workflow_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "workflows")
        
        if not os.path.exists(workflow_dir):
            return "没有保存的工作流"
        
        try:
            files = [f for f in os.listdir(workflow_dir) if f.endswith(".json")]
            if not files:
                return "没有保存的工作流"
            
            result = "保存的工作流列表:\n"
            for i, file in enumerate(files, 1):
                # 尝试读取文件获取元数据
                filepath = os.path.join(workflow_dir, file)
                try:
                    with open(filepath, "r", encoding="utf-8") as f:
                        data = json.load(f)
                    metadata = data.get("metadata", {})
                    action_count = metadata.get("action_count", 0)
                    created_at = metadata.get("created_at", "未知")
                    result += f"{i}. {file} - 操作数: {action_count}, 创建时间: {created_at}\n"
                except:
                    result += f"{i}. {file} - 无法读取元数据\n"
            
            return result
        except Exception as e:
            logger.error(f"列出工作流失败: {str(e)}")
            return f"列出工作流失败: {str(e)}"
    
    def delete_workflow(self, filename: str) -> str:
        """删除工作流文件"""
        workflow_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "workflows")
        filepath = os.path.join(workflow_dir, filename)
        
        # 如果文件路径不存在，尝试添加.json扩展名
        if not os.path.exists(filepath) and not filename.endswith(".json"):
            filepath += ".json"
        
        if not os.path.exists(filepath):
            return f"工作流文件不存在: {filepath}"
        
        try:
            os.remove(filepath)
            logger.info(f"删除工作流文件: {filepath}")
            return f"成功删除工作流文件: {filename}"
        except Exception as e:
            logger.error(f"删除工作流文件失败: {str(e)}")
            return f"删除工作流文件失败: {str(e)}"

# 创建全局工作流管理器实例
workflow_manager = None

# 检查模块可用性函数
def is_available():
    """检查工作流管理模块是否可用
    
    Returns:
        bool: 模块是否可用（只要有任一依赖可用，模块就被视为可用）
    """
    # 只要有任一依赖可用，模块就被视为可用
    return PYAUTOGUI_AVAILABLE or KEYBOARD_AVAILABLE or KEYBOARD_HOOK_AVAILABLE

# 初始化函数
def initialize():
    """初始化工作流管理模块
    
    Returns:
        bool: 是否初始化成功
    """
    global workflow_manager
    try:
        # 无论依赖是否完整，都尝试初始化，但会在日志中反映功能状态
        workflow_manager = WorkflowManager()
        
        # 检查功能状态
        available_functions = []
        if PYAUTOGUI_AVAILABLE:
            available_functions.append("鼠标控制")
        if KEYBOARD_AVAILABLE:
            available_functions.append("键盘控制")
        if KEYBOARD_HOOK_AVAILABLE:
            available_functions.append("键盘钩子")
        
        if available_functions:
            logger.info(f"工作流管理模块初始化成功，可用功能: {', '.join(available_functions)}")
        else:
            logger.warning("工作流管理模块初始化成功，但缺少所有必要依赖，功能受限")
        
        return True
    except Exception as e:
        logger.error(f"工作流管理模块初始化失败: {str(e)}")
        return False

# 便捷函数 - 录制工作流
def start_recording(workflow_name=None):
    """开始录制工作流"""
    if workflow_manager:
        return workflow_manager.start_recording(workflow_name)
    else:
        logger.error("工作流管理器未初始化")
        return False

# 便捷函数 - 停止录制
def stop_recording():
    """停止录制工作流"""
    if workflow_manager:
        return workflow_manager.stop_recording()
    else:
        logger.error("工作流管理器未初始化")
        return False

# 便捷函数 - 保存工作流
def save_workflow(name=None):
    """保存工作流"""
    if workflow_manager:
        return workflow_manager.save_workflow(name)
    else:
        logger.error("工作流管理器未初始化")
        return None

# 便捷函数 - 播放工作流
def play_workflow(name):
    """播放工作流"""
    if workflow_manager:
        return workflow_manager.play_workflow(name)
    else:
        logger.error("工作流管理器未初始化")
        return False

# 便捷函数 - 停止播放
def stop_playback():
    """停止播放工作流"""
    if workflow_manager:
        return workflow_manager.stop_playback()
    else:
        logger.error("工作流管理器未初始化")
        return False

# 便捷函数 - 列出工作流
def list_workflows():
    """列出所有工作流"""
    if workflow_manager:
        return workflow_manager.list_workflows()
    else:
        logger.error("工作流管理器未初始化")
        return []

# 便捷函数 - 删除工作流
def delete_workflow(name):
    """删除工作流"""
    if workflow_manager:
        return workflow_manager.delete_workflow(name)
    else:
        logger.error("工作流管理器未初始化")
        return False

# 如果直接运行此模块，执行简单测试
if __name__ == "__main__":
    print("=== 工作流管理模块测试 ===")
    if initialize():
        print("1. 列出可用工作流:")
        workflows = list_workflows()
        for wf in workflows:
            print(f"   - {wf}")
        
        print("\n2. 测试录制和回放功能需要交互式操作")
        print("   请在实际应用中使用 start_recording(), stop_recording(), 和 play_workflow() 方法")
    else:
        print("工作流管理模块初始化失败")